package com.zytech.zspider.task.impl.http;

import com.gargoylesoftware.htmlunit.*;
import com.zytech.modules.lang.Ghost;
import com.zytech.modules.lang.MemberFilters;
import com.zytech.modules.lang.Strings;
import com.zytech.zspider.core.TaskDefinition;
import com.zytech.zspider.core.TaskDefinitionHelper;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Map;

/**
 * @author siuming
 */
final class WebClientFactory {

    static final CookieManager COOKIE_MANAGER = new CookieManager();

    /**
     * @param settings
     * @return
     */
    static WebClient of(Map<String, String> settings) {
        if (null != WebClientHolder.get()) {
            return WebClientHolder.get();
        }

        WebClient webClient = new WebClient(determineBrowserVersion(settings));
        withOptions(webClient, settings);

        webClient.setCookieManager(COOKIE_MANAGER);
        webClient.getCookieManager().setCookiesEnabled(true);
        webClient.setAjaxController(new NicelyResynchronizingAjaxController());
        WebClientHolder.set(webClient);
        return webClient;
    }

    private static void withOptions(WebClient webClient, Map<String, String> props) {
        String timeout = TaskDefinitionHelper.getSetting(props, TaskDefinition.Settings.HTTP_TIMEOUT, "15000");
        webClient.getOptions().setTimeout(Integer.valueOf(timeout));

        String jsEnabled = TaskDefinitionHelper.getSetting(props, TaskDefinition.Settings.HTTP_SCRIPT_ENABLED, "true");
        webClient.getOptions().setJavaScriptEnabled(Boolean.valueOf(jsEnabled));

        String cssEnabled = TaskDefinitionHelper.getSetting(props, TaskDefinition.Settings.HTTP_CSS_ENABLED, "false");
        webClient.getOptions().setCssEnabled(Boolean.valueOf(cssEnabled));

        String followRedirect = TaskDefinitionHelper.getSetting(props, TaskDefinition.Settings.HTTP_FOLLOW_REDIRECT, "true");
        webClient.getOptions().setRedirectEnabled(Boolean.valueOf(followRedirect));

        String[] vals = Strings.split(TaskDefinitionHelper.getSetting(props, TaskDefinition.Settings.HTTP_PROXY, ""), ":");
        if (vals.length == 3) {
            webClient.getOptions().setProxyConfig(new ProxyConfig(vals[1], Integer.valueOf(vals[2])));
        }
    }

    private static BrowserVersion determineBrowserVersion(Map<String, String> props) {
        try {

            String browser = TaskDefinitionHelper.getSetting(props, TaskDefinition.Settings.HTTP_BROWSER_VERSION, "");
            Ghost<?> ghost = Ghost.me(BrowserVersion.class);
            Field[] fields = ghost.listFields(
                    MemberFilters.fieldMod(Modifier.FINAL)
                            .and(MemberFilters.fieldMod(Modifier.STATIC))
                            .and(MemberFilters.fieldType(BrowserVersion.class))
                            .and(MemberFilters.fieldName(browser.toUpperCase()))
            );

            return fields.length == 0 ? BrowserVersion.getDefault() : (BrowserVersion) ghost.ejector(null, fields[0]).eject();
        } catch (Exception ignore) {
            return BrowserVersion.getDefault();
        }
    }

    private WebClientFactory() {
    }
}
